package com.ck.company.service.impl;

import java.text.ParseException;
import java.util.*;

import com.ck.constant.DeviceGroupConstant;
import com.ck.constant.ProgramPutinConstant;
import com.ck.util.DateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ck.common.service.OperationLogService;
import com.ck.company.service.CpDeviceGroupService;
import com.ck.company.service.CpDeviceInfoService;
import com.ck.constant.BusinessConstant;
import com.ck.constant.ModuleConstant;
import com.ck.dao.DeviceGroupMapper;
import com.ck.exception.ServiceException;
import com.ck.model.common.DeviceGroup;
import com.ck.model.common.OperationLog;
import com.ck.model.common.User;
import com.ck.model.company.dto.CpDeviceGroupListDTO;
import com.ck.model.company.dto.CpDeviceGroupTreeListDTO;
import com.ck.model.company.dto.CpDeviceGroupTreeListForProgramDTO;

@Service(value = "deviceGroupService")
public class CpDeviceGroupServiceImpl implements CpDeviceGroupService {

    @Autowired
    private DeviceGroupMapper deviceGroupMapper;
    @Autowired
    private OperationLogService operationLogService;
    @Autowired
    private CpDeviceInfoService deviceInfoService;

    /**
     * 所有终端分组列表
     *
     * @return List<DeviceGroupListDTO>
     */
    @Override
    public List<CpDeviceGroupListDTO> listAllDeviceGroup(String companyCode) {
        return deviceGroupMapper.listAllDeviceGroup(companyCode);
    }

    /**
     * 保存终端分组
     *
     * @param deviceGroup TbDeviceGroup类型对象
     * @param user
     * @param ip
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void saveDeviceGroup(DeviceGroup deviceGroup, User user, String ip) throws ServiceException {
        String companyCode = user.getCompanyCode();
        //检查分组名是否存在
        DeviceGroup nameDeviceGroup = deviceGroupMapper.getDeviceGroupByGroupName(companyCode, deviceGroup.getGroupName());
        if (nameDeviceGroup != null) {
            throw new ServiceException("分组名已存在,不能重复");
        }
        //检查分组码是否存在
        DeviceGroup codeDeviceGroup = deviceGroupMapper.getDeviceGroupByGroupCode(companyCode, deviceGroup.getGroupCode());
        if (codeDeviceGroup != null) {
            throw new ServiceException("分组码已存在,不能重复");
        }
        deviceGroup.setUpdateTime(System.currentTimeMillis());
        //保存终端分组
        deviceGroup.setCompanyCode(companyCode);
        if (deviceGroup.getParentId() != null && deviceGroup.getParentId().equals(DeviceGroupConstant.ALL_DEVICE_GROUP_ID)) {
            deviceGroup.setParentId(null);
        }
        deviceGroupMapper.saveDeviceGroup(deviceGroup);

        //保存操作日志
        saveOperationLog("添加终端分组:" + deviceGroup.getGroupName(), user, ip);
    }


    /**
     * 更新终端分组
     *
     * @param deviceGroup TbDeviceGroup类型对象
     * @param user
     * @param ip
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void updateDeviceGroup(DeviceGroup deviceGroup, User user, String ip) throws ServiceException {
        String companyCode = user.getCompanyCode();
        // 分组主键id
        Long deviceGroupId = deviceGroup.getDeviceGroupId();
        // 分组名
        String groupName = deviceGroup.getGroupName();
        DeviceGroup nameDeviceGroup = deviceGroupMapper.getDeviceGroupByGroupName(companyCode, groupName);
        if (nameDeviceGroup != null) {
            // 如果已存在分组名相同且主键不同，则重复
            if (groupName.equals(nameDeviceGroup.getGroupName()) && !deviceGroupId.equals(nameDeviceGroup.getDeviceGroupId())) {
                throw new ServiceException("分组名已存在,不能重复");
            }
        }
        // 分组码
        String groupCode = deviceGroup.getGroupCode();
        DeviceGroup codeDeviceGroup = deviceGroupMapper.getDeviceGroupByGroupCode(companyCode, groupCode);
        if (codeDeviceGroup != null) {
            // 如果已存在分组码相同且主键不同，则重复
            if (groupCode.equals(codeDeviceGroup.getGroupCode()) && !deviceGroupId.equals(codeDeviceGroup.getDeviceGroupId())) {
                throw new ServiceException("分组码已存在,不能重复");
            }
        }
        deviceGroup.setUpdateTime(System.currentTimeMillis());
        if (deviceGroup.getParentId() != null && deviceGroup.getParentId().equals(DeviceGroupConstant.ALL_DEVICE_GROUP_ID)) {
            deviceGroup.setParentId(null);
        }
        deviceGroupMapper.updateDeviceGroup(deviceGroup);

        //保存操作日志
        saveOperationLog("更新终端分组:" + deviceGroup.getGroupName(), user, ip);
    }

    /**
     * 获取终端分组
     *
     * @param deviceGroupId 终端分组ID
     */
    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public DeviceGroup getDeviceGroup(String companyCode, Long deviceGroupId) {
        return deviceGroupMapper.getDeviceGroupById(companyCode, deviceGroupId);
    }

    /**
     * 删除终端分组
     *
     * @param deviceGroupId 终端分组ID
     * @param groupName     终端分名称
     * @param groupId       分组ID
     * @param user          登录用户
     * @param ip            用户IP
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void deleteDeviceGroup(Long deviceGroupId, String groupName, Long groupId, User user, String ip) {
        String companyCode = user.getCompanyCode();
        // 将所属终端的分组置为空
        deviceInfoService.updateDeviceGroupNull(companyCode, groupId);
        //删除终端分组
        deviceGroupMapper.deleteDeviceGroupById(companyCode, deviceGroupId);
        //保存操作日志
        saveOperationLog("删除终端分组:" + groupName, user, ip);
    }

    /**
     * 通过父ID获取终端分组列表
     *
     * @param parentId 父ID
     * @return List<TbDeviceGroup>
     */
    @Override
    public List<DeviceGroup> listDeviceGroupByParentId(String companyCode, Long parentId) {
        return deviceGroupMapper.listDeviceGroupByParentId(companyCode, parentId);
    }


    /**
     * 所有终端树形分组列表
     *
     * @return List<DeviceGroupTreeListDTO>
     */
    @Override
    public List<CpDeviceGroupTreeListDTO> listAllDeviceGroupTree(String companyCode) {
        return deviceGroupMapper.listAllDeviceGroupTree(companyCode);
    }

    /**
     * 移动终端到分组
     *
     * @param deviceGroupId 分组ID
     * @param deviceCodes   终端唯一编码，多个用逗号分隔
     * @param user
     * @param ip
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void moveDeviceGroup(Long deviceGroupId, String deviceCodes, User user, String ip) {
        String companyCode = user.getCompanyCode();
        deviceGroupMapper.moveDeviceGroup(companyCode, deviceGroupId, Arrays.asList(deviceCodes.split(",")));
        //保存操作日志
        saveOperationLog("移动终端code:[" + deviceCodes + "]到分组Id:[" + deviceGroupId + "]", user, ip);
    }

    /**
     * 查询所有终端分组
     *
     * @param companyCode 商家编号
     * @return List<CpDeviceGroupTreeListForProgramDTO>
     */
    @Override
    public List<CpDeviceGroupTreeListForProgramDTO> listAllDeviceGroupTreeForProgram(String companyCode) {
        return deviceGroupMapper.listAllDeviceGroupTreeForProgram(companyCode);
    }

    /**
     * 查询树形分组列表
     *
     * @param companyCode 商家编码
     * @param startTimeL  投放开始时间
     * @param endTimeL    投放结束时间
     * @return List<CpDeviceGroupTreeListDTO>
     */
    @Override
    public List<CpDeviceGroupTreeListDTO> deviceGroupTreeListByTime(String companyCode, Long startTimeL, Long endTimeL) {
        // 根据投放时间段查询已投放的终端组
        List<String> deviceGroupIds = deviceGroupMapper.listAllDeviceGroupByTime(companyCode, startTimeL, endTimeL);
        if (CollectionUtils.isNotEmpty(deviceGroupIds)) {
            removeDuplicate(deviceGroupIds);
        }
        return deviceGroupMapper.deviceGroupTreeListByTime(companyCode, deviceGroupIds);
    }

    /**
     * 查询投放终端组时的终端组树
     *
     * @param user      登录的用户
     * @param startTime 节目投放开始时间
     * @param endTime   节目投放结束时间
     * @return List<CpDeviceGroupTreeListDTO>
     * @throws ParseException
     */
    @Override
    public List<CpDeviceGroupTreeListDTO> treeToGroup(User user, String startTime, String endTime) throws ParseException {
        List<CpDeviceGroupTreeListDTO> treeMenu = new ArrayList<>();
        Long startTimeL = null;
        Long endTimeL = null;
        if (StringUtils.isNotBlank(startTime)) {
            startTimeL = DateUtils.stringTimeToLongTimeStamp(startTime, DateUtils.PATTEN_YMD_HMS1);
        } else {
            startTimeL = ProgramPutinConstant.UNLIMIT_START_TIME;
        }
        if (StringUtils.isNotBlank(endTime)) {
            endTimeL = DateUtils.stringTimeToLongTimeStamp(endTime, DateUtils.PATTEN_YMD_HMS1);
        } else {
            endTimeL = ProgramPutinConstant.UNLIMIT_END_TIME;
        }
        //查询在时间段内的终端组（不包含插播节目已投放的）
        List<CpDeviceGroupTreeListDTO> putinGroupList = this.deviceGroupTreeListByTime(user.getCompanyCode(), startTimeL, endTimeL);
        //根节点
        List<CpDeviceGroupTreeListDTO> rootMenu = new ArrayList<>();
        for (CpDeviceGroupTreeListDTO nav : putinGroupList) {
            //父节点为null的，为根节点。
            if (nav.getPid() == null || "".equals(nav.getPid())) {
                rootMenu.add(nav);
            }
        }
        if (CollectionUtils.isEmpty(rootMenu)) {
            rootMenu = putinGroupList;
        }
        //为根菜单设置子菜单，getClild是递归调用的
        for (CpDeviceGroupTreeListDTO nav : rootMenu) {
            /* 获取根节点下的所有子节点 使用getChild方法*/
            List<CpDeviceGroupTreeListDTO> childList = getChild(nav.getDeviceGroupId(), putinGroupList);
            //给根节点设置子节点
            nav.setChildren(childList);
        }
        //自创一个节点叫“全部分组”,他是所有已有的分组的父类
        CpDeviceGroupTreeListDTO specialMenu = new CpDeviceGroupTreeListDTO();
        specialMenu.setLabel(DeviceGroupConstant.ALL_DEVICE_GROUP_NAME);
        specialMenu.setDeviceGroupId(DeviceGroupConstant.ALL_DEVICE_GROUP_ID);
        specialMenu.setGroupCode(DeviceGroupConstant.ALL_DEVICE_GROUP_CODE);
        specialMenu.setOpen(true);
        specialMenu.setChildren(rootMenu);
        //自创一个最高节点叫“未分组”,所有未分组的终端在该组
        CpDeviceGroupTreeListDTO noGroup = new CpDeviceGroupTreeListDTO();
        noGroup.setLabel(DeviceGroupConstant.NO_DEVICE_GROUP_NAME);
        noGroup.setGroupCode(DeviceGroupConstant.NO_DEVICE_GROUP_CODE);
        noGroup.setDeviceGroupId(DeviceGroupConstant.NO_DEVICE_GROUP_ID);
        noGroup.setOpen(false);
        treeMenu.add(specialMenu);
        treeMenu.add(noGroup);
        return treeMenu;
    }

    /**
     * 查询投放终端时的终端组树
     *
     * @param user          登录的用户
     * @param deviceGroupId 分组ID
     * @return List<CpDeviceGroupTreeListForProgramDTO>
     */
    @Override
    public List<CpDeviceGroupTreeListForProgramDTO> treeToDevice(User user, String deviceGroupId) {
        List<CpDeviceGroupTreeListForProgramDTO> treeMenu = new ArrayList<>();
        //查询所有菜单
        List<CpDeviceGroupTreeListForProgramDTO> allMenu = this.listAllDeviceGroupTreeForProgram(user.getCompanyCode());
        List<String> idList = new ArrayList<>();
        if (StringUtils.isNotBlank(deviceGroupId)) {
            String[] idArr = deviceGroupId.split(",");
            idList.addAll(Arrays.asList(idArr));
        }
        //根节点
        List<CpDeviceGroupTreeListForProgramDTO> rootMenu = new ArrayList<>();
        for (CpDeviceGroupTreeListForProgramDTO nav : allMenu) {
            nav.setOpen(true);
            if (null != nav.getDeviceGroupId() && idList.contains(nav.getDeviceGroupId().toString())) {
                nav.setChecked(true);
            }
            //父节点为null的，为根节点。
            if (nav.getPid() == null || "".equals(nav.getPid())) {
                rootMenu.add(nav);
            }
        }
        //为根菜单设置子菜单，getClild是递归调用的
        for (CpDeviceGroupTreeListForProgramDTO nav : rootMenu) {
            /* 获取根节点下的所有子节点 使用getChild方法*/
            List<CpDeviceGroupTreeListForProgramDTO> childList = getChildForProgram(nav.getDeviceGroupId(), allMenu);
            //给根节点设置子节点
            nav.setChildren(childList);
        }
        //自创一个最高节点叫“全部分组”,他是所有已有的分组的父类
        CpDeviceGroupTreeListForProgramDTO specialMenu = new CpDeviceGroupTreeListForProgramDTO();
        specialMenu.setLabel(DeviceGroupConstant.ALL_DEVICE_GROUP_NAME);
        specialMenu.setDeviceGroupId(DeviceGroupConstant.ALL_DEVICE_GROUP_ID);
        specialMenu.setGroupCode(DeviceGroupConstant.ALL_DEVICE_GROUP_CODE);
        specialMenu.setOpen(true);
        specialMenu.setChildren(rootMenu);
        if (StringUtils.isBlank(deviceGroupId)) {
            specialMenu.setChecked(true);
        }

        //自创一个最高节点叫“未分组”,所有未分组的终端在该组
        CpDeviceGroupTreeListForProgramDTO noGroup = new CpDeviceGroupTreeListForProgramDTO();
        noGroup.setLabel(DeviceGroupConstant.NO_DEVICE_GROUP_NAME);
        noGroup.setGroupCode(DeviceGroupConstant.NO_DEVICE_GROUP_CODE);
        noGroup.setDeviceGroupId(DeviceGroupConstant.NO_DEVICE_GROUP_ID);
        noGroup.setOpen(false);
        treeMenu.add(specialMenu);
        treeMenu.add(noGroup);
        return treeMenu;
    }

    /**
     * 去重
     *
     * @param list 待去重的集合
     */
    private static void removeDuplicate(List<String> list) {
        LinkedHashSet<String> set = new LinkedHashSet<>(list.size());
        set.addAll(list);
        list.clear();
        list.addAll(set);
        list.removeAll(Collections.singleton(null));
    }

    /**
     * 保存操作日志
     *
     * @param operContent 操作内容
     * @param user        登录用户
     * @param ip          用户IP
     */
    private void saveOperationLog(String operContent, User user, String ip) {
        operationLogService.saveSuccessOperationLog(operContent, ModuleConstant.MODULE_DEVICE_MNG, user, ip);
    }

    /**
     *    * 获取子节点
     *    * @param id 父节点id
     *    * @param allMenu 所有菜单列表
     *    * @return 每个根节点下，所有子菜单列表
     *    
     */
    private List<CpDeviceGroupTreeListDTO> getChild(Long id, List<CpDeviceGroupTreeListDTO> allMenu) {
        //子菜单
        List<CpDeviceGroupTreeListDTO> childList = new ArrayList<>();
        for (CpDeviceGroupTreeListDTO nav : allMenu) {
            /**
             * 遍历所有节点，将所有菜单的父id与传过来的根节点的id比较
             * 相等说明：为该根节点的子节点。
             */
            if (nav.getPid() != null && (id.toString()).equals(nav.getPid())) {
                childList.add(nav);
            }
        }
        //递归
        for (CpDeviceGroupTreeListDTO nav : childList) {
            nav.setChildren(getChild(nav.getDeviceGroupId(), allMenu));
        }
        //如果节点下没有子节点，返回一个空List（递归退出）
        if (childList.size() == 0) {
            return new ArrayList<>();
        }
        return childList;
    }

    /**
     * 获取子节点
     *
     * @param id      父节点id
     * @param allMenu 所有菜单列表
     * @return 每个根节点下，所有子菜单列表
     *    
     */
    private List<CpDeviceGroupTreeListForProgramDTO> getChildForProgram(Long id, List<CpDeviceGroupTreeListForProgramDTO> allMenu) {
        //子菜单
        List<CpDeviceGroupTreeListForProgramDTO> childList = new ArrayList<>();
        for (CpDeviceGroupTreeListForProgramDTO nav : allMenu) {
            /**
             * 遍历所有节点，将所有菜单的父id与传过来的根节点的id比较
             * 相等说明：为该根节点的子节点。
             */
            if (nav.getPid() != null && (id.toString()).equals(nav.getPid())) {
                childList.add(nav);
            }
        }
        //递归
        for (CpDeviceGroupTreeListForProgramDTO nav : childList) {
            nav.setChildren(getChildForProgram(nav.getDeviceGroupId(), allMenu));
        }
        //如果节点下没有子节点，返回一个空List（递归退出）
        if (childList.size() == 0) {
            return new ArrayList<>();
        }
        return childList;
    }
}
